import random
import math
import sys
import util    

"""
 introduces noisy into the route
 outputs: route with gpsCoords
 traceList has the format: lat, long, horz error, timestamp, speed, speed error

"""
def run1(traceList, interval = 10, speed = 10): #noisyLocations = "cNoise.txt", 
    trace = traceList    
    noisyTrace = simpleNoise(complexNoise(trace), interval, speed)
    return noisyTrace

def complexNoise(trace):
    """
     currently, complex noise only removes random GPS coordinates to simulate GPS loss
     because GPS loss probably occurs in blobs, i.e. if a gps signal is lost, it is likely lost for a period of time
     if one point is lost, then the probability that the next point is lost increases
     """
    newTrace = []
    prob = 0.1
    for pts in trace:
        if random.random() > prob :
            newTrace.append(pts)
            if prob > 0.1:
                prob = prob / 1.2
        else:
            if prob < 0.6:
                prob = prob * 1.2
    return newTrace

def addGaussian(lat,lon,sd):
    oneMeterLat = 1/111000.0

    angle = random.random() * 180.0
    dist = random.gauss(0,sd) / random.uniform(2,10)
    
    newLat = math.sin(angle / 180.0 * math.pi) * dist * oneMeterLat
    oneDegreeLong  = 111 * math.cos(lat * math.pi / 180) * 1000.0
    oneMeterLong   = 1 / oneDegreeLong
    newLon = math.cos(angle / 180.0 * math.pi) * dist * oneMeterLong
    
    if random.uniform(0,100) < 0.5:
        dist = random.gauss(0,sd * random.uniform(2,10))
        newLat = math.sin(angle / 180.0 * math.pi) * dist * oneMeterLat
        oneDegreeLong  = 111 * math.cos(lat * math.pi / 180) * 1000.0
        oneMeterLong   = 1 / oneDegreeLong
        newLon = math.cos(angle / 180.0 * math.pi) * dist * oneMeterLong

    return [lat + newLat, lon + newLon, dist]

def simpleNoise(trace, interval, speed):
    """ simple noise, occurs normally
     according to http://edu-observatory.org/gps/gps_accuracy.html, http://www.usps.org/e_stuff/files/0-1gps_lg_errata22may07.pdf
     GPS error is about 10 meters
     according to http://www.fes.uwaterloo.ca/crs/geog165/gcoords.htm
     a difference of 10 meters is different depending on the location
     for 1 degree latitude, its approximately 111 km
     10 meters in latitude is a difference of 1/(11100)
    
     for 1 degree long, it is 111km * cos(lat)
    
     interval is needed because GPS tends to be more accurate for faster speeds
     interval is the number of seconds between each sample
    """
    gpsInaccuracy = 50 # in meters
    noisyPairs = []
    prevTrace = trace[0]
    
    for lat,lon,horzDil,tim,speed,speedAcc in trace:
        temp = addGaussian(lat,lon, gpsInaccuracy)
        speedAcc = random.gauss(10,10) # add speed inaccuracy
        noisyPairs.append(temp + [tim,speed + speedAcc, speedAcc])
    return noisyPairs

"""

def run(traceFile = "sampleGPS.txt", outputFile = '', noisyLocations = "cNoise.txt", delimiter = ",", interval = 10):
    print "STARTING"
    
    # f should be a file containing the GPS coordinates in the format
    # latitude longitude
    f = open(traceFile, "rb")
    lines = [x.replace('\r\n','') for x in f]
    f.close()
    
    trace = []
    for coords in lines:
        temp = coords.split(delimiter)
        if len(temp) == 3:
            trace.append([eval(temp[1]), eval(temp[2])])
        elif len(temp) == 2:
            trace.append([eval(temp[0]), eval(temp[1])])
	    
    if len(temp) == 3:
        f = open(traceFile, "w")
        for lat,long in trace:
            f.write(str(lat))
            f.write(",")
            f.write(str(long))
            f.write("\n")
        f.close()
    
    noisyTrace = simpleNoise(complexNoise(trace), interval)
    #noisyTrace = simpleNoise(complexNoise(trace, noisyLocations))
    
    #print "ORIGINAL TRACES: " + str(lines)
    #print "# ORIGINAL TRACES: " + str(len(lines))
    #print "NOISY TRACES: " + str(noisyTrace)
    #print "# NOISY TRACES: " + str(len(noisyTrace))
    if outputFile == '':
	f = open(traceFile.replace(".txt", "") + "noisy.txt", 'w')
    else:
        f = open(outputFile, 'w')
    for lat,long in noisyTrace:
        f.write(str(lat))
        f.write(",")
        f.write(str(long))
        f.write("\n")
    f.close()
    
    print "FINISHED"




if len(sys.argv) == 5:
    print "NOT IMPLEMENTED YET"
elif len(sys.argv) == 4:
    print "NOT IMPLEMENTED YET"
elif len(sys.argv) == 3:
    print sys.argv[1]
    print sys.argv[2]
    run(sys.argv[1], sys.argv[2])
elif len(sys.argv) == 2:
    print sys.argv[1]
    run(sys.argv[1])
elif len(sys.argv) == 1:
    run()
else:
    print "noisy.py <input trace file> <output trace file> <noisy location data> <delimiter>"
    print "<noisy loc data> and <delimiter> aren't implemented yet"
    
"""   
# =============================================================== #
# Currently not in use                                            #
# =============================================================== #

def latInBtwn(lat, tL, rB):
    if lat < tL and lat > rB:
        return True
    return False

def longInBtwn(long, tL, rB):
    if long > tL and long < rB:
        return True
    if tL > 0 and rB < 0:
        if long > tL and long > rB:
            return True
    return False

def complexNoiseArea(fileName):
    # complexNoiseArea
    # file format
    # top left lat, long bottom right lat, long
    f = open(fileName, 'rb')
    temp = [x.replace('\r\n','') for x in f]
    f.close()
    
    areas = []
    for lines in temp:
        t = lines.split(" ")
        if len(t) != 4:
            print "ERROR: too many coordinates in complex noisy area"
        areas.append([[eval(t[0]), eval(t[1])], [eval(t[2]), eval(t[3])]])
    return areas

def complexNoise1(trace, fileName):
    # adds complex noise to the trace
    # if the gps pts are in a "bad" area, significant noise will be added
    newTrace = []
    areas = complexNoiseArea(fileName)
    # [[ [TL pt], [BR pt] ], [next pair]...]
    done = []
    
    for area in areas:
        tLLat,tLLong  = area[0]
        bRLat,bRLong  = area[1]
        
        for lat,long in trace:
            if latInBtwn(lat, tLLat, bRLat) and longInBtwn(long, tLLong, bRLong) and not ([lat, long] in done):
                if random.choice([True, False]):
                    newTrace.append([lat + random.random()/random.uniform(1,100), long + random.random()/random.uniform(1,100)])
                done.append([lat, long])
                    
    for x in trace:
        if not (x in done):
            newTrace.append(x)

    return newTrace